package models;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

import org.apache.log4j.Logger;

import frame.FeatureHandler;


/**
 * @author Rishi Das Roy
 *
 * @Organization Institute Of Genomics & Integrative Biology
 */
public class ResultByPreference {
	private static Logger log = Logger.getLogger(ResultByPreference.class);

	public static void preference(BaseModel[] predModel, String filePath, FeatureHandler lfh) throws IOException {
		BufferedWriter lBw = new BufferedWriter(new FileWriter(filePath+"_Result.txt"));
		lBw.write("Actual,Prediction,score,prot_id"+System.getProperty("line.separator"));
		for (int i = 0; i < lfh.getActualLabels().size(); i++) {
			int actualLabel =  lfh.getActualLabels().get(i);
			float voteScore = 0;
			for (BaseModel model : predModel) {
				if(model.getResult().getPredictedLabels().get(i)>0)
					voteScore++;
			}
			if(voteScore>0){
				lBw.write(actualLabel+",1,"+voteScore+","+lfh.getId().get(i)+System.getProperty("line.separator"));
			}else{
				lBw.write(actualLabel+",-1,"+voteScore+","+lfh.getId().get(i)+System.getProperty("line.separator"));
			}

			if(voteScore*actualLabel>=0){
				if(voteScore>0){
					mTruePositive++;
				}else{
					mTrueNegative++;
				}

			}
		}
		lBw.close();
		mFalsePositive = lfh.getNegativeCounts() - mTrueNegative;
		mFalseNegative = lfh.getPositiveCounts() - mTruePositive;
		mTotal = lfh.getActualLabels().size();

		writeResult(filePath+"_Result.csv");

	}

	private static long mTruePositive = 0;
	private static long mTrueNegative = 0;
	private List<Float> mPredictedLabels;
	private static long mFalsePositive;
	private static long mFalseNegative;
	private static long mTotal;

	public long getFalseNegative() {
		return mFalseNegative;
	}

	public long getFalsePositive() {
		return mFalsePositive;
	}

	public List<Float> getPredictedLabels() {
		return mPredictedLabels;
	}

	public long getTrueNegative() {
		return mTrueNegative;
	}

	public long getTruePositive() {
		return mTruePositive;
	}

	public static void writeResult(String pFilePath) throws IOException {
		BufferedWriter lBw = new BufferedWriter(new FileWriter(pFilePath));
		lBw.write("Confusion Matrix"+System.getProperty("line.separator"));
		lBw.write(",,Actual"+System.getProperty("line.separator"));
		lBw.write(",,GS,NGS,Total"+System.getProperty("line.separator"));
		lBw.write("Predicted,GS,"+mTruePositive+","+mFalsePositive+","+(mTruePositive+mFalsePositive)+System.getProperty("line.separator"));
		lBw.write("Predicted,NGS,"+mFalseNegative+","+mTrueNegative+","+(mTrueNegative+mFalseNegative)+System.getProperty("line.separator"));
		lBw.write(",Total,"+(mTruePositive+mFalseNegative)+","+(mTrueNegative+mFalsePositive)+System.getProperty("line.separator"));
		lBw.write(System.getProperty("line.separator")+System.getProperty("line.separator"));

		lBw.write("Accuracy ,"+getAccuracy()+System.getProperty("line.separator"));
		lBw.write("Balance Accuracy ,"+getBAC()+System.getProperty("line.separator"));
		lBw.write("MCC ,"+getMcc()+System.getProperty("line.separator"));
		lBw.write("Class,GS,NGS"+System.getProperty("line.separator"));
		lBw.write("Recall ,"+getP_Recall()+","+getN_Recall()+System.getProperty("line.separator"));
		lBw.write("Precision ,"+getP_Precision()+","+getN_Precision()+System.getProperty("line.separator"));
		lBw.write("F-Measure ,"+getP_Fmeasure()+","+getN_Fmeasure()+System.getProperty("line.separator"));
		lBw.close();
	}

	private static float getBAC() {

		return (getP_Recall()+getN_Recall())/2;
	}

	private static double getMcc() {
		double square_root = Math.sqrt((mTruePositive+mFalsePositive)*(mTruePositive+mFalseNegative)
					*(mTrueNegative+mFalsePositive)*(mTrueNegative+mFalseNegative));
		if(square_root<=0)
			return 0;


		return (mTruePositive*mTrueNegative - mFalsePositive*mFalseNegative)/square_root;
	}

	private static float getAccuracy() {
		return (float)(mTruePositive+mTrueNegative)/mTotal;
	}

	private static float getN_Fmeasure() {
		float denominator = (getN_Precision()+getN_Recall());
		if(denominator<=0)
			return 0;


		return ((float)2*getN_Precision()*getN_Recall()/denominator);
	}

	private static float getP_Fmeasure() {
		float denominator = (getP_Precision()+getP_Recall());
		if(denominator<=0)
			return 0;


		return ((float)2*getP_Precision()*getP_Recall()/denominator);
	}

	private static float getN_Precision() {
		long denominator = (mTrueNegative+mFalseNegative);
		if(denominator<=0)
			return 0;


		return ((float)mTrueNegative/denominator);
	}

	private static float getP_Precision() {
		long denominator = (mTruePositive + mFalsePositive);
		if(denominator<=0)
			return 0;


		return ((float)mTruePositive/denominator);
	}

	private static float getN_Recall() {
		long denominator = (mTrueNegative + mFalsePositive);
		if(denominator<=0)
			return 0;


		return ((float)mTrueNegative/denominator);
	}

	/**
	 * Sensitivity;Recall;
	 * true positive rate, hit rate
	 * @return
	 */
	private static float getP_Recall() {
		long denominator = (mTruePositive + mFalseNegative);
		if(denominator<=0)
			return 0;

		return ((float)mTruePositive/denominator);
	}

	public static void main(String[] args) {
		mTruePositive = 21;
		mTrueNegative = 2411;
		mFalsePositive = 622;
		mFalseNegative = 60;
	}
}


